import direct.directbase.DirectStart
from direct.actor import Actor
from direct.fsm import FSM #importing finate state machine. not needed though.
from pandac.PandaModules import *
from direct.interval.IntervalGlobal import *
from direct.task import Task #all games require heavy use of tasks
from direct.showbase.DirectObject import DirectObject
import math

#simple creating and showing an environment.
#environ = loader.loadModel("models/defaults/environment")
environ=loader.loadModel("samples/Roaming-Ralph/models/world")
environ.reparentTo(render)
environ.setScale(20,20,.5)

#giving control of the mouse to uiser
base.disableMouse()
base.camera.setPos(Point3(0, 200, 75))
base.camera.setHpr(0,-30,0)

class Rider (DirectObject):
    def __init__(self):
        
        self.actor = Actor.Actor("models/Animations/walking_anim", 
                         {"stand-walk":"models/Animations/stand2walkS", #for walking. this may be obsolete
                          "walk":"models/Animations/walking_anim", #for walking. i believe this is the proper walking animation
                          "runAT":"models/Animations/runningAT"}) #the running animation from stand-run2
    
        self.actor.setScale(.05,.05,.05)
        
        self.actor.reparentTo(render)
        #self.actor.setPlayRate(.7, 'walk')
        self.stand2walkControl=self.actor.getAnimControl("stand-walk")
            
        self.mode="walk" #to distinguish between modes. probably obsolete.
        
        self.keyMap = {"left":0, "right":0, "up":0, "down":0, "mouse-1":0, "mouse-3":0, "enter":0}

        
        self.accept("arrow_up", self.setKey, ["up", 1])
        self.accept("arrow_down", self.setKey, ["down", 1])
        self.accept("arrow_right", self.setKey, ["right", 1])
        self.accept("arrow_left", self.setKey, ["left", 1])
        self.accept("shift", self.setKey, ["shift", 1])
        self.accept("mouse1", self.setKey, ["mouse-1", 1])
        self.accept("mouse2", self.setKey, ["mouse-2", 1])
        self.accept("mouse3", self.setKey, ["mouse-3", 1])
        self.accept("enter", self.setKey, ["enter", 1])

        
        self.accept("arrow_up-up", self.setKey, ["up", 0])
        self.accept("arrow_down-up", self.setKey, ["down", 0])
        self.accept("arrow_right-up", self.setKey, ["right", 0])
        self.accept("arrow_left-up", self.setKey, ["left", 0])
        self.accept("mouse1-up", self.setKey, ["mouse-1", 0])
        self.accept("mouse2-up", self.setKey, ["mouse-2", 0])
        self.accept("mouse3-up", self.setKey, ["mouse-3", 0])
        self.accept("enter", self.setKey, ["enter", 0])
        
        self.step="R"
        self.state="stand"
        self.startP=0
        
        self.actor.pose("stand-walk", 0)
        
        self.speed=0/30
        
        self.prevMouseX=0
        self.prevMouseY=0

        #stats
        self.maxSpeed=90/30
        self.accelScale=1.0/210.0
        
        base.win.movePointer(0, base.win.getProperties().getXSize()/2, base.win.getProperties().getYSize()/2)
        self.prevMouseX=0
        self.prevMouseY=0      
        #mouse variables
        #self.mouseHStats=[0,0,0]#limit, scale, scaleH
        #self.mousePStats=[0,0,0]#limit, limitBack, scale
        
        self.actor.pose("runAT", 1)
        #taskMgr.add(self.mouseHR, "mouse heading")
        #taskMgr.add(self.mouseP, "mouse pitch")
        taskMgr.add(self.RunAT, "running with ATs")
    
    def setKey(self, key, value):
        self.keyMap[key] = value
#suggestions: put "stats" in __init__, apply mouseP to run2, make it start large screen, exit button, actually progress lolol, put in acceleration

    def RunAT(self, task):
        if self.keyMap["mouse-1"]!=0 and self.keyMap["mouse-3"]==0 and self.state=="stand":
            if self.step=="R":
                self.actor.setSx(self.actor, -1)
                self.step="L"
            self.actor.play("runAT", fromFrame=2, toFrame=41)
            self.frame=task.frame
            
            
            self.speed=self.speed+(1/30)
            self.state="stand-runL1"
        #add mouseP and adjust the pitch instead of speed
        elif self.state=="stand-runL1":
            self.mouseHR(30, 15, 1.0/60.0)
            self.speed=self.speed+(1/30)
            if self.frame+39<=task.frame:
                self.state="runL1"
        if self.state=="runL1" and self.keyMap["mouse-1"]!=0:
            minSpeed=0/30
            offSet=10
            self.mouseHR(30, 15, 1.0/60.0)
            self.mouseP(45, 0, 70)
            
            if self.speed+(self.actor.getP()-offSet)*self.accelScale>=minSpeed and self.speed+(self.actor.getP()-offSet)*self.accelScale<=self.maxSpeed:#would be
                self.speed=self.speed+(self.actor.getP()-offSet)*self.accelScale
            elif self.speed+(self.actor.getP()-offSet)*self.accelScale<minSpeed:
                self.speed=minSpeed
            elif self.speed+(self.actor.getP()-offSet)*self.accelScale>self.maxSpeed:
                self.speed=self.maxSpeed
                
            if self.actor.getCurrentFrame("runAT")!=42:
                self.actor.pose("runAT", 42)
        if self.state=="runL1" and self.keyMap["mouse-1"]==0:
            self.actor.play("runAT", fromFrame=43, toFrame=74)
            self.startP=self.actor.getP()
            self.state="runL1-runL2"
        #adjust the pitch from where it is to a neural position (10 degrees?)
        if self.state=="runL1-runL2":
            self.actor.setP(self.actor.getP()-(self.startP/196.0))
            if self.actor.getCurrentFrame()>=74:
                self.state="runL2"
        if self.state=="runL2":
            minSpeed=0/30
            offSet=10
            self.mouseHR(30, 15, 1.0/60.0)
            if self.speed+(self.actor.getP()-offSet)*self.accelScale>=minSpeed and self.speed+(self.actor.getP()-offSet)*self.accelScale<=self.maxSpeed:#would be
                self.speed=self.speed+(self.actor.getP()-offSet)*self.accelScale
            elif self.speed+(self.actor.getP()-offSet)*self.accelScale<minSpeed:
                self.speed=minSpeed
            elif self.speed+(self.actor.getP()-offSet)*self.accelScale>self.maxSpeed:
                self.speed=self.maxSpeed
                
        '''
        #need new animation for leg switch
        
        if self.state=="runL2" and self.keyMap["mouse-3"]!=0 and self.keyMap["mouse-1"]==0:
            self.actor.play("runAT")            
            self.state="runL2-runR1"
        if self.state=="runL2-runR1":
            if self.frame+42<=task.frame:
                self.state=runR1
        '''

            
        if self.keyMap["mouse-3"]!=0 and self.keyMap["mouse-1"]==0 and self.state=="stand":
            if self.step=="L":
                self.actor.setSx(self.actor, -1)
                self.step="R"
            self.actor.play("runAT", fromFrame=2, toFrame=41)
            self.frame=task.frame
                                                                                                                                                                                                                                                                                                                                  
            self.speed=self.speed+(.5/30)
            self.state="stand-runR1"
        elif self.state=="stand-runR1":
            self.mouseHR(30, 15, 1.0/60.0)
            self.speed=self.speed+(.5/30)
            if self.frame+39<=task.frame:
                self.state="runR1" 
        if self.state=="runR1" and self.keyMap["mouse-3"]!=0:
            minSpeed=0/30
            offSet=10
            self.mouseHR(30, 15, 1.0/60.0)
            self.mouseP(45, 0, 45)
            
            if self.speed+(self.actor.getP()-offSet)*self.accelScale>=minSpeed and self.speed+(self.actor.getP()-offSet)*self.accelScale<=self.maxSpeed:#would be
                self.speed=self.speed+(self.actor.getP()-offSet)*self.accelScale
            elif self.speed+(self.actor.getP()-offSet)*self.accelScale<minSpeed:
                self.speed=minSpeed
            elif self.speed+(self.actor.getP()-offSet)*self.accelScale>self.maxSpeed:
                self.speed=self.maxSpeed
                
            if self.actor.getCurrentFrame("runAT")!=42:
                self.actor.pose("runAT", 42)
        if self.state=="runR1" and self.keyMap["mouse-3"]==0:
            self.actor.play("runAT", fromFrame=43, toFrame=74)
            self.startP=self.actor.getP()
            self.state="runR1-runR2"
        if self.state=="runR1-runR2":
            self.actor.setP(self.actor.getP()-(self.startP/196.0))
            if self.actor.getCurrentFrame()>=74:
                self.state="runR2"                  
        if self.state=="runR2":
            minSpeed=0/30
            offSet=10
            self.mouseHR(30, 15, 1.0/60.0)
            if self.speed+(self.actor.getP()-offSet)*self.accelScale>=minSpeed and self.speed+(self.actor.getP()-offSet)*self.accelScale<=self.maxSpeed:#would be
                self.speed=self.speed+(self.actor.getP()-offSet)*self.accelScale
            elif self.speed+(self.actor.getP()-offSet)*self.accelScale<minSpeed:
                self.speed=minSpeed
            elif self.speed+(self.actor.getP()-offSet)*self.accelScale>self.maxSpeed:
                self.speed=self.maxSpeed
        '''
        #need new animation for leg switch
        
        if self.state=="runR2" and self.keyMap["mouse-1"]!=0:
            self.actor.play("runAT")            
            self.state="runR2-runL1"
        if self.state=="runR2-runL1":
            if self.frame+42<=task.frame:
                self.state=runL1
        '''
        
        base.camera.setPos(self.actor.getX()-(200*math.sin((self.actor.getH()*math.pi/180))),
                           self.actor.getY()+(200*math.cos((self.actor.getH()*math.pi/180))),
                           base.camera.getZ())
        base.camera.lookAt(self.actor)
        
        self.move()
#        if self.keyMap["enter"]!=0:
#            print "It is finished"
#            return Task.done    
        return Task.cont
    
    def move(self):
        x=self.speed*math.sin((self.actor.getH()*math.pi/180))
        y=self.speed*math.cos((self.actor.getH()*math.pi/180))
        self.actor.setPos(self.actor.getX()+x, self.actor.getY()-y, self.actor.getZ())


    def mouseHR(self, limit, scale, scaleH):
        xBorder=.9
        try:
            if base.mouseWatcherNode.getMouseX()>xBorder:
                if (self.actor.getR()+(self.prevMouseX-xBorder)*scale)>=-limit:
                    self.actor.setR(self.actor.getR()+(self.prevMouseX-xBorder)*scale)
                else:
                    self.actor.setR(-limit)
                base.win.movePointer(0,
                                     base.win.getProperties().getXSize()*(1-xBorder)/2,
                                     base.win.getProperties().getYSize()*((-(base.mouseWatcherNode.getMouseY())+1)/2))
                self.prevMouseX=-xBorder
            elif base.mouseWatcherNode.getMouseX()<-xBorder:
                if (self.actor.getR()+(self.prevMouseX-(-xBorder))*scale)<=limit:
                    self.actor.setR(self.actor.getR()+(self.prevMouseX-(-xBorder))*scale)
                else:
                    self.actor.setR(limit)
                base.win.movePointer(0,
                                     base.win.getProperties().getXSize()*(1-((1-xBorder)/2)),
                                     base.win.getProperties().getYSize()*((-(base.mouseWatcherNode.getMouseY())+1)/2))            
                self.prevMouseX=xBorder
            elif self.prevMouseX!=base.mouseWatcherNode.getMouseX():
                if (self.actor.getR()+(self.prevMouseX-base.mouseWatcherNode.getMouseX())*scale)>=-limit and (self.actor.getR()+(self.prevMouseX-base.mouseWatcherNode.getMouseX())*scale)<=limit:
                    self.actor.setR(self.actor.getR()+(self.prevMouseX-base.mouseWatcherNode.getMouseX())*scale)
                elif (self.actor.getR()+(self.prevMouseX-base.mouseWatcherNode.getMouseX())*scale)<-limit:
                    self.actor.setR(-limit)
                elif (self.actor.getR()+(self.prevMouseX-base.mouseWatcherNode.getMouseX())*scale)>limit:
                    self.actor.setR(limit)
                self.prevMouseX=base.mouseWatcherNode.getMouseX()
        except AssertionError:
             self.prevMouseX=0
             self.prevMouseY=0
             base.win.movePointer(0,
                                  base.win.getProperties().getXSize()/2,
                                  base.win.getProperties().getYSize()/2)
        self.actor.setH(self.actor.getH()+(self.actor.getR()*scaleH))#seperate
        
            
    def mouseP(self, limit, limitBack, scale):
        yBorder=.9
        try:
            if base.mouseWatcherNode.getMouseY()>yBorder:
                if (self.actor.getP()+(yBorder-self.prevMouseY)*scale)<=limit:
                    self.actor.setP(self.actor.getP()+(yBorder-self.prevMouseY)*scale)
                else:
                    self.actor.setP(limit)
                base.win.movePointer(0,
                                     base.win.getProperties().getXSize()*((base.mouseWatcherNode.getMouseX()+1)/2),
                                     base.win.getProperties().getYSize()*(1-((1-yBorder)/2)))
                self.prevMouseY=-yBorder
            elif base.mouseWatcherNode.getMouseY()<-yBorder:
                if (self.actor.getP()+(-yBorder-self.prevMouseY)*scale)>=limitBack:
                    self.actor.setP(self.actor.getP()+(-yBorder-self.prevMouseY)*scale)
                else:
                    self.actor.setP(limitBack)
                base.win.movePointer(0,
                                     base.win.getProperties().getXSize()*((base.mouseWatcherNode.getMouseX()+1)/2),
                                     base.win.getProperties().getYSize()*(1-yBorder)/2)
                self.prevMouseY=yBorder  
            elif self.prevMouseY!=base.mouseWatcherNode.getMouseY():
                if (self.actor.getP()+(base.mouseWatcherNode.getMouseY()-self.prevMouseY)*scale)<=limit and (self.actor.getP()+(base.mouseWatcherNode.getMouseY()-self.prevMouseY)*scale)>=limitBack:
                    self.actor.setP(self.actor.getP()+(base.mouseWatcherNode.getMouseY()-self.prevMouseY)*scale)
                elif (self.actor.getP()+(base.mouseWatcherNode.getMouseY()-self.prevMouseY)*scale)>limit:
                    self.actor.setP(limit)
                elif (self.actor.getP()+(base.mouseWatcherNode.getMouseY()-self.prevMouseY)*scale)<limitBack:
                    self.actor.setP(limitBack)
                self.prevMouseY=base.mouseWatcherNode.getMouseY()
        except AssertionError:
            self.prevMouseX=0
            self.prevMouseY=0
            base.win.movePointer(0,
                                 base.win.getProperties().getXSize()/2,
                                 base.win.getProperties().getYSize()/2)

 
Rider()

run()
